#include "sw_game_state_main.h"

#include <allegro5\allegro.h>
#include <allegro5\allegro_primitives.h>
#include <allegro5\allegro_image.h>
#include <allegro5\allegro_audio.h>
#include <allegro5\allegro_acodec.h>
#include <math.h>
#include "sw_input_manager.h"
#include "sw_game_manager.h"
#include "sw_contact_listener.h"
#include "sw_game_map.h"
#include "sw_ml_room.h"
#include "sw_game_state_menu.h"
#include "sw_sound_manager.h"
#include "globals.h"
#include <Box2D\Box2D.h>

sw_game_state_main::sw_game_state_main() {
	background = new sw_background("images/bkgd.png");
	sw_ml_room map("maps/testmap.txt");

	// world
	b2Vec2 gravity(0.0f, 2*9.8f);
	box2d_world = new b2World(gravity);

	// contact listener
	box2d_world->SetContactListener(new sw_contact_listener);

	// chain
	b2BodyDef bd;
	b2Body* chainbody = box2d_world->CreateBody(&bd);
	chainbody->SetUserData(this);

	b2ChainShape shape;
	vslength = map.get_boundary_vertex_num();
	vs = new b2Vec2[vslength];
	for (int i=0; i<vslength; i++) {
		vs[i] = *(new b2Vec2(map.get_boundary_vertex_x(i),map.get_boundary_vertex_y(i)));
	}
	shape.CreateLoop(vs, vslength);
	chainbody->CreateFixture(&shape, 0.0f);
	
	uint16 filstatic = 0x001;
	uint16 fillayers[8];
	fillayers[0] = 0x002;
	fillayers[1] = 0x004;
	fillayers[2] = 0x008;
	fillayers[3] = 0x010;
	fillayers[4] = 0x020;
	fillayers[5] = 0x040;
	fillayers[6] = 0x080;
	fillayers[7] = 0x100;
	uint16 filyou =    0x200;
	

	// your sphere in layer 2
	b2BodyDef bodyDef;
	bodyDef.type = b2_dynamicBody;
	bodyDef.position.Set(map.get_start_x(), map.get_start_y());
	bodyDef.angle = 1.0;
	shizzle_body = box2d_world->CreateBody(&bodyDef);
	shizzle_body->SetUserData(this);
	b2CircleShape dynamicSphere;
	dynamicSphere.m_radius = 0.98f;
	b2PolygonShape dynamicBox;
	dynamicBox.SetAsBox(1.0f, 1.0f);
	b2FixtureDef fixtureDef;
	fixtureDef.shape = &dynamicSphere;
	//fixtureDef.shape = &dynamicBox;
	fixtureDef.density = 0.5f;
	fixtureDef.friction = 0.0f;
	fixtureDef.restitution = 0.0f;
	fixtureDef.filter.categoryBits = fillayers[1] | filyou;
	fixtureDef.filter.maskBits = filstatic | fillayers[1] | fillayers[0];
	shizzle_body->CreateFixture(&fixtureDef);
	b2Vec2 velv(0.0, 1.0);
	shizzle_body->SetLinearVelocity(velv);
	shizzle_body->SetLinearDamping(0.4f);

	//// tile body
	//b2BodyDef tilebodydef;
	//tilebodydef.type = b2_staticBody;
	////bodyDef.type = b2_dynamicBody;
	//tilebodydef.position.Set(15.0f, 12.0f);
	//tilebodydef.angle = 29.0;
	//tilebody = box2d_world->CreateBody(&tilebodydef);
	//b2PolygonShape tilebox;
	//tilebox.SetAsBox(2.0f, 1.0f);
	//b2FixtureDef tilefixturedef;
	//fixtureDef.shape = &tilebox;
	//fixtureDef.density = 0.5f;
	//fixtureDef.friction = 0.0f;
	//fixtureDef.restitution = 0.0f;
	//fixtureDef.filter.categoryBits = fillayer2 | filyou;
	//fixtureDef.filter.maskBits = filstatic | fillayer2 | fillayer1;
	//tilebody->CreateFixture(&fixtureDef);
	////tilebody->SetLinearVelocity(velv);

	// enemy bodies
	_enemy_bodies_num = map.get_enemy_num();
	_enemy_bodies = new b2Body*[_enemy_bodies_num];
	for (int i=0; i<_enemy_bodies_num; i++) {
		float x = map.get_enemy_x(i);
		float y = map.get_enemy_y(i);
		int layer = map.get_enemy_layer(i);
	
		b2BodyDef blockDef;
		blockDef.type = b2_dynamicBody;
		blockDef.position.Set(x, y);
		blockDef.angle = 0.0f;
		_enemy_bodies[i] = box2d_world->CreateBody(&blockDef);
		_enemy_bodies[i]->SetUserData(this);
		//b2PolygonShape dynamicBox;
		//dynamicBox.SetAsBox(1.0f, 1.0f);
		b2CircleShape enemysphere;
		enemysphere.m_radius = 0.7f;
		b2FixtureDef bfixtureDef;
		//bfixtureDef.shape = &dynamicSphere;
		bfixtureDef.shape = &enemysphere;
		bfixtureDef.density = 0.3f;
		bfixtureDef.friction = 0.0f;
		bfixtureDef.restitution = 0.7f;
		bfixtureDef.filter.categoryBits = fillayers[layer-1];
		bfixtureDef.filter.maskBits = filstatic | fillayers[layer-1] | filyou;
		_enemy_bodies[i]->CreateFixture(&bfixtureDef);
		b2Vec2 zerov(0.0f, 0.0f);
		_enemy_bodies[i]->SetLinearVelocity(zerov);
	}

	// tiles
	int ncols = map.get_tiles_numcols();
	int nrows = map.get_tiles_numrows();
	_tile_width = map.get_tiles_width();
	_tile_height = map.get_tiles_height();
	for (int i=0; i<ncols; i++) {
		for (int j=0; j<nrows; j++) {
			if (map.get_tile(i, j)) {
				b2BodyDef blockDef;
				blockDef.type = b2_staticBody;
				blockDef.position.Set(map.get_tiles_start_x()+i*_tile_width, map.get_tiles_start_y()+j*_tile_height);
				blockDef.angle = 0.0f;
				b2Body* tilebody = box2d_world->CreateBody(&blockDef);
				_tile_bodies.push_back(tilebody);
				tilebody->SetUserData(this);
				b2PolygonShape staticBox;
				staticBox.SetAsBox(map.get_tiles_width()/2, map.get_tiles_height()/2);
				b2FixtureDef bfixtureDef;
				//bfixtureDef.shape = &dynamicSphere;
				bfixtureDef.shape = &staticBox;
				bfixtureDef.density = 0.3f;
				bfixtureDef.friction = 0.0f;
				bfixtureDef.restitution = 0.0f;
				//bfixtureDef.filter.categoryBits = filstatic;
				//bfixtureDef.filter.maskBits = filstatic | filyou;
				tilebody->CreateFixture(&bfixtureDef);
				//b2Vec2 zerov(0.0f, 0.0f);
			}
		}
	}

	//sound = false;
	//sound_count = 0;

}

sw_game_state_main::~sw_game_state_main() {
	//delete[] sprites;
	delete box2d_world;
	delete background;
	delete[] vs;
}

void sw_game_state_main::draw_on_screen() {
	b2Vec2 position;
	float32 angle;
	position = shizzle_body->GetPosition();
	//angle = shizzle_body->GetAngle();
	float toplx = position.x - global_pixel_width*global_screen_width/2;
	float toply = position.y - global_pixel_height*global_screen_height/2;
	
	background->draw_on_screen(toplx, toply);

	//b2Body* body = box2d_world->GetBodyList();
	for(int i=0; i<vslength; i++) {
		float x1 = (vs[i].x - toplx) / global_pixel_width;
		float x2 = (vs[(i+1)%vslength].x - toplx) / global_pixel_width;
		float y1 = (vs[i].y - toply) / global_pixel_height;
		float y2 = (vs[(i+1)%vslength].y - toply) / global_pixel_height;
		al_draw_line(x1, y1, x2, y2, al_map_rgb(255, 0, 0), 1);
	}
	
	// enemies
	for (int i=0; i<_enemy_bodies_num; i++) {
		position = _enemy_bodies[i]->GetPosition();
		angle = _enemy_bodies[i]->GetAngle();
		// draw a light blue sphere
		al_draw_filled_circle((position.x-toplx) / global_pixel_width, (position.y-toply) / global_pixel_height,
			0.7f / global_pixel_width, al_map_rgb(0, 255, 255));
	}

	// you
	position = shizzle_body->GetPosition();
	angle = shizzle_body->GetAngle();
	al_draw_filled_circle((position.x-toplx) / global_pixel_width, (position.y-toply) / global_pixel_height,
		1.0f / global_pixel_width, al_map_rgb(0, 0, 255));

	// tiles
	for (int i=0; i<_tile_bodies.size(); i++) {
		b2Body* body = _tile_bodies.at(i);
		position = body->GetPosition();
		al_draw_filled_rectangle((position.x-_tile_width/2-toplx) / global_pixel_width, (position.y-_tile_height/2-toply) / global_pixel_height,
			(position.x+_tile_width/2-toplx) / global_pixel_width,
			(position.y+_tile_height/2-toply) / global_pixel_height,
			al_map_rgb(255, 0, 0));
	}

	// sound
	global_sound_manager->play_sound(sw_sound_manager::SW_SOUND_BGM, false);
	//if (sound) {
	//	global_sound_manager->play_sound(SW_SOUND_ENEMY_DEATH);
	//	sound_count ++;
	//	if (sound_count > 1) {
	//		sound_count = 0;
	//		sound = false;
	//	}
	//}

	// global life
	al_draw_filled_rectangle(210 - global_life * 200 / 100, 10, 210, 30, al_map_rgb(0, 255, 0));

}

void sw_game_state_main::compute_timestep() {
	b2Vec2 position;
	position = shizzle_body->GetPosition();
	float toplx = position.x;
	float toply = position.y;
	//position = blockbody->GetPosition();
	//float toprx = position.x;
	//float topry = position.y;
	//float xx = toprx-toplx;
	//float yy = topry-toply;
	//float dist = sqrt(xx*xx + yy*yy);
	//if (dist>0) {
	//	life -= 0.02 / dist / dist;
	//}

	if (global_input_manager->times_pressed(ALLEGRO_KEY_SPACE)>0) {
		global_game_state->set_game_state_sub(new sw_game_state_menu());
		return;
	}
	
	box2d_world->ClearForces();
	if (global_input_manager->times_pressed(ALLEGRO_KEY_UP)>0) {
		b2Vec2 impv(0.0f, -20.0f);
		b2Vec2 pointv(0.5f, 0.5f);
		shizzle_body->ApplyLinearImpulse(impv, shizzle_body->GetPosition());
	}
	if (global_input_manager->pressed(ALLEGRO_KEY_LEFT)) {
		b2Vec2 impv(-32.0f, 0.0f);
		b2Vec2 pointv(1.0f, 0.5f);
		shizzle_body->ApplyForce(impv, shizzle_body->GetPosition());
	}
	if (global_input_manager->pressed(ALLEGRO_KEY_RIGHT)) {
		b2Vec2 impv(32.0f, 0.0f);
		b2Vec2 pointv(1.0f, 0.5f);
		shizzle_body->ApplyForce(impv, shizzle_body->GetPosition());
	}
	box2d_world->Step(1.0f/60.0f, 8, 3);

}